package com.dudu.utils;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import org.apache.log4j.Logger;

import core.util.IoUtils;

/**
 * 音频相关工具类
 * @author zx
 *
 */
public class AudioUtils {

	private static final int DEFAULT_WAV_HZ = 16000;

	private static final int DEFAULT_WAV_BIT = 16;

	private static final Logger LOG = Logger.getLogger(AudioUtils.class);

	public static boolean pcmToWav(String src, String target) {
		return pcmToWav(src, target, DEFAULT_WAV_HZ, DEFAULT_WAV_BIT);
	}

	public static boolean pcmToWav(String src, String target, int hz, int bit) {
		FileInputStream is = null;
		FileOutputStream os = null;
		ByteArrayOutputStream byos = null;
		boolean success = false;
		try {
			is = new FileInputStream(src);
			os = new FileOutputStream(target);
			// 计算长度
			byte[] buf = new byte[1024 * 4];
			int size = is.read(buf);
			int PCMSize = 0;
			byos = new ByteArrayOutputStream();
			while (size != -1) {
				byos.write(buf, 0, size);
				PCMSize += size;
				size = is.read(buf);
			}
			// 填入参数，比特率等等。
			WaveHeader header = new WaveHeader();
			// 长度字段 = 内容的大小（PCMSize) +
			// 头部字段的大小(不包括前面4字节的标识符RIFF以及fileLength本身的4字节)
			header.fileLength = PCMSize + (44 - 8);
			header.FmtHdrLeth = 16;
			// header.BitsPerSample = 16;
			header.BitsPerSample = (short) bit;
			header.Channels = 1;
			header.FormatTag = 0x0001;
			header.SamplesPerSec = hz;
			header.BlockAlign = (short) (header.Channels * header.BitsPerSample / 8);
			header.AvgBytesPerSec = header.BlockAlign * header.SamplesPerSec;
			header.DataHdrLeth = PCMSize;
			byte[] h = header.getHeader();
			assert h.length == 44; // WAV标准，头部应该是44字节
			os.write(h, 0, h.length);
			os.write(byos.toByteArray());
			success = true;
		} catch (Exception err) {
			err.printStackTrace();
			LOG.error("文件[" + src + "]转换失败", err);
		} finally {
			IoUtils.close(byos);
			IoUtils.close(os);
			IoUtils.close(is);
		}
		return success;
	}

	private static class WaveHeader {
		public final char fileID[] = { 'R', 'I', 'F', 'F' };
		public int fileLength;
		public char wavTag[] = { 'W', 'A', 'V', 'E' };
		public char FmtHdrID[] = { 'f', 'm', 't', ' ' };
		public int FmtHdrLeth;
		public short FormatTag;
		public short Channels;
		public int SamplesPerSec;
		public int AvgBytesPerSec;
		public short BlockAlign;
		public short BitsPerSample;
		public char DataHdrID[] = { 'd', 'a', 't', 'a' };
		public int DataHdrLeth;

		public byte[] getHeader() throws IOException {
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			WriteChar(bos, fileID);
			WriteInt(bos, fileLength);
			WriteChar(bos, wavTag);
			WriteChar(bos, FmtHdrID);
			WriteInt(bos, FmtHdrLeth);
			WriteShort(bos, FormatTag);
			WriteShort(bos, Channels);
			WriteInt(bos, SamplesPerSec);
			WriteInt(bos, AvgBytesPerSec);
			WriteShort(bos, BlockAlign);
			WriteShort(bos, BitsPerSample);
			WriteChar(bos, DataHdrID);
			WriteInt(bos, DataHdrLeth);
			bos.flush();
			byte[] r = bos.toByteArray();
			bos.close();
			return r;
		}

		private void WriteShort(ByteArrayOutputStream bos, int s) throws IOException {
			byte[] mybyte = new byte[2];
			mybyte[1] = (byte) ((s << 16) >> 24);
			mybyte[0] = (byte) ((s << 24) >> 24);
			bos.write(mybyte);
		}

		private void WriteInt(ByteArrayOutputStream bos, int n) throws IOException {
			byte[] buf = new byte[4];
			buf[3] = (byte) (n >> 24);
			buf[2] = (byte) ((n << 8) >> 24);
			buf[1] = (byte) ((n << 16) >> 24);
			buf[0] = (byte) ((n << 24) >> 24);
			bos.write(buf);
		}

		private void WriteChar(ByteArrayOutputStream bos, char[] id) {
			for (int i = 0; i < id.length; i++) {
				char c = id[i];
				bos.write(c);
			}
		}
	}

}
